﻿using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Gwn.Library.MvpVm.Base;
using Gwn.Library.MvpVm.Constants;
using Gwn.Library.MvpVm.Entities;
using Gwn.Library.MvpVm.Events;
using Gwn.Library.MvpVm.Extensions;
using Gwn.Library.MvpVm.Interfaces;
using Gwn.Library.MvpVm.ViewModels;
using Gwn.Module.UserManager.Interfaces;
using Gwn.Module.UserManager.Types;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;

namespace Gwn.Module.UserManager
{
    public class UserManagerPresenter : PresenterBase
    {
        #region Fields

        private int _desktopCommandHack = 0;
        private ListBox UserList { get; set; }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the app controller.
        /// </summary>
        /// <value>The app controller.</value>
        [Dependency]
        public IApplicationController AppController { get; set; }

        /// <summary>
        /// Gets or sets the BLL.
        /// </summary>
        /// <value>The BLL.</value>
        [Dependency]
        public IBusinessLogicLayer Bll { get; set; }

        /// <summary>
        /// Gets the security view model.
        /// </summary>
        /// <value>The security view model.</value>
        public UserCommandViewModel UserViewModel { get { return (UserCommandViewModel)ViewModel; } }

        #endregion 

        /// <summary>
        /// Called by application controller when view is activated
        /// </summary>
        public override void ViewActivated()
        {
            base.ViewActivated();

            // Wire-up the UserList ListBox if not already wired-up
            if (UserList == null)
                WireUpUserListBox();
        }

        /// <summary>
        /// Executed after Presenter and its components are resolved
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            // Subscribe to process events
            EventAggregator.GetEvent<ProcessEvent>().Subscribe(HandleProcessEvents);

            // Get the user list - handled by the HandleProcessEvents below
            Bll.GetUserListAsync();

            // Deactivates this view and allows the SecurityView to be shown
            AppController.ActivateView(ConstantModules.SecurityModule);
        }


        /// <summary>
        /// Handles the process events.
        /// </summary>
        /// <param name="e">The <see cref="Gwn.Library.MvpVm.Events.ProcessEventArgs"/> instance containing the event data.</param>
        public void HandleProcessEvents(ProcessEventArgs e)
        {
            // Always show errors
            if (e.IsError) UserViewModel.StatusMessage = e.FriendlyMessage;

            // We'll only handle UserManagerProcessType
            var processType = e.ProcessType.GetProcessType<UserManagerProcessType>();

            if(processType== UserManagerProcessType.ListData)
            {
                if (e.IsError) return;

                // Retrieve the data and populate view model
                UserViewModel.UserList = e.GetData<ObservableCollection<User>>();

                // Set the selected user to the first record
                UserViewModel.SelectedUser = UserViewModel.UserList.FirstOrDefault();
            }

            // Display any messages for UserManagerProcessType
            if (processType != UserManagerProcessType.NotApplicable)
                UserViewModel.StatusMessage = e.FriendlyMessage;

        }

        /// <summary>
        /// Handles the execute command by resolving the provided
        /// command parameter against
        /// </summary>
        /// <param name="executeCommandPara">The para.</param>
        public override void HandleCommandExecuteMethod(object executeCommandPara)
        {
            // Set the view model state with the button being
            // requested so that the RaiseCanExecuteChanged will
            // have it for HandleCommandCanExecuteMethod() below
            UserViewModel.AddEditUndoDeleteCommandState = executeCommandPara;

            // Refresh all buttons based on button clicked (executeCommandPara)
            UserViewModel.Command.RaiseCanExecuteChanged();

            // Call baseclass functionality which uses the parameter
            // to determine which command to execute (Unity factory
            // configured in UserManagerModule for IPresenterCommand)
            base.HandleCommandExecuteMethod(executeCommandPara);
        }


        /// <summary>
        /// Handles the command can execute method.
        /// </summary>
        /// <param name="canExecuteParameter">The can execute parameter.</param>
        /// <returns></returns>
        public override bool HandleCommandCanExecuteMethod(object canExecuteParameter)
        {
            // The desktop platform will send in nulls (versus the actual
            // command parameter) during initialization - disable undo/save button
            // which are in offsets 3 and 4.
            if (canExecuteParameter == null)
            {
                _desktopCommandHack++;
                return _desktopCommandHack != 3 && _desktopCommandHack != 4;
            }

            // [Activate login view] button is always enabled
            if (canExecuteParameter.ToString().Contains("Login"))
                return true;

            // If we're initializing buttons (silverlight/Phone) then return 
            // true for all values except for Undo/Save (they are disabled)
            if (UserViewModel.AddEditUndoDeleteCommandState == null)
                return !(canExecuteParameter.ToString().Contains("Undo")
                        || canExecuteParameter.ToString().Contains("Save"));

            // If here then we are no longer initializing.  Use 
            // extension method to determine if button is enabled
            // or disabled (Add, Edit, Undo and Delete logic)
            var result = UserViewModel.AddEditUndoDeleteCommandState
                .GetState(canExecuteParameter);

            // Return result
            return result;
        }


        /// <summary>
        /// Wires up user list box so that the SelectionChange event is
        /// respected by all platforms
        /// </summary>
        private void WireUpUserListBox()
        {
            var view = (IUserControl) View;

            // When the view is loaded we'll want to get a reference
            // to the lstUserList control (in DataTemplate) so that
            // we can subscribe to its SelectionChanged event
            view.Loaded += (s, e) =>
                {
                    // Get a reference to our list box
                    UserList = view.FindChildName<ListBox>("lstUserList");
                    
                    // Default to the first item in the list
                    if (UserList.Items.Count > 0)
                        UserList.SelectedIndex = 0;

                    // Subscribe to Selection Change events
                    UserList.SelectionChanged += (s1, e1) =>
                        {
                            // If no data then return
                            if (e1.AddedItems.Count == 0) return;

                            // Get the selected user record and
                            // Update view model if not null
                            var user = e1.AddedItems[0] as User;
                            if (user != null)
                                UserViewModel.SelectedUser = user;
                        };
                };
        }
    }
}
